home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 301-325 / disk_319 / cnewssrc / cnews.orig.lzh / libc / fgetmfs.c < prev    next >
C/C++ Source or Header  |  1989-06-27  |  3KB  |  131 lines

  1. /*
  2.  * fgetmfs - read an arbitrarily long, possibly continued line;
  3.  * return a pointer to it, in malloced memory.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <sys/types.h>
  9. #include <fgetmfs.h>
  10. #include "libc.h"
  11.  
  12. #define max(a,b) ((a) > (b)? (a): (b))
  13. #define min(a,b) ((a) < (b)? (a): (b))
  14.  
  15. /* One could make these arguments, with defaults. */
  16. #define INITLN 90        /* initial allocation per line */
  17. #define GROWLN 200        /* additional allocation size */
  18.  
  19. /* getseg returns */
  20. #define FAILED 0
  21. #define HITLIMIT 1
  22. #define OKAY 2
  23.  
  24. static unsigned sz;        /* bytes currently allocated (in line) */
  25. static int incr;        /* for sz */
  26. static char *line;        /* current allocation */
  27. static char *segment;        /* start of line segment in "line" */
  28. static char *morep;        /* last byte possibly containing input */
  29.  
  30. /*
  31.  * `fget malloced, flagged string' with continuations and limit on bytes.
  32.  * The limit is like fgets's; limit-1 bytes can be read.  -1 means "no limit".
  33.  */
  34. char *
  35. fgetmfs(fp, limit, cont)
  36. FILE *fp;
  37. register int limit, cont;        /* honour \ continuations? */
  38. {
  39.     /* allocate room for an initial segment of a line */
  40.     sz = INITLN;
  41.     incr = GROWLN;
  42.     if (limit >= 0 && sz > limit)
  43.         sz = limit;
  44.     line = malloc(sz);
  45.     if (line == NULL)
  46.         return NULL;        /* no memory, can't go on */
  47.     segment = line;
  48.     morep = line + sz - 2;
  49.  
  50.     /* read all lines, including continuations */
  51.     do {
  52.         /* read the first segment of a line */
  53.         *morep = '\0';            /* mark end of segment */
  54.         if (fgets(segment, (int)sz-(segment-line), fp) == NULL) {
  55.             free(line);        /* EOF: give up */
  56.             return NULL;
  57.         }
  58.  
  59.         /* read more of this line, if it didn't fit */
  60.         while (*morep != '\0' && *morep != '\n') {
  61.             register int code = getseg(fp, limit);
  62.  
  63.             if (code == FAILED)
  64.                 return NULL;
  65.             else if (code == HITLIMIT)
  66.                 break;
  67.         }
  68.     } while (cont && ismore(fp, cont));
  69.     return realloc(line, (unsigned)(strlen(line)+1));    /* save space */
  70. }
  71.  
  72. static int
  73. getseg(fp, limit)
  74. FILE *fp;
  75. register int limit;
  76. {
  77.     register int oldsz = sz;
  78.  
  79.     /* extend the allocation, within limit */
  80.     incr = GROWLN;
  81.     sz += incr;
  82.     if (limit >= 0 && sz > limit) {
  83.         sz = limit;
  84.         incr = sz - oldsz;
  85.     }
  86.     if (incr <= 0)            /* hit the limit? */
  87.         return HITLIMIT;
  88.     line = realloc(line, sz);
  89.     if (line == NULL)
  90.         return FAILED;        /* no memory, can't go on */
  91.     /* -1 starts on the terminating NUL of the prev. segment */
  92.     segment = line + oldsz - 1;
  93.     morep = line + sz - 2;        /* recompute for new line, sz */
  94.  
  95.     /* read the next segment */
  96.     *morep = '\0';
  97.     /* +1 because segment includes terminating NUL of the prev. segment */
  98.     if (fgets(segment, incr+1, fp) == NULL) {
  99.         free(line);        /* EOF: give up */
  100.         return FAILED;
  101.     }
  102.     return OKAY;
  103. }
  104.  
  105. static int
  106. ismore(fp, cont)
  107. register FILE *fp;
  108. int cont;
  109. {
  110.     register char *nlp;
  111.  
  112.     /* got a whole line: is it to be continued? */
  113.     if (incr > 0 && cont && (nlp = rindex(line, '\n')) != NULL &&
  114.         nlp > line && *--nlp == '\\') {
  115.         *nlp = '\0';            /* delete "\\\n" */
  116.         segment = nlp;
  117.             if (cont == CONT_NOSPC) {
  118.             register int c;
  119.  
  120.             /* discard leading whitespace */
  121.             while ((c = getc(fp)) != EOF && c != '\n' &&
  122.                isascii(c) && isspace(c))
  123.                 ;
  124.             if (c != EOF)
  125.                 (void) ungetc(c, fp);
  126.             }
  127.         return 1;            /* read next line */
  128.     } else
  129.         return 0;
  130. }
  131.